import { createElement } from "../createElement";
import {
  contextMap,
  contextSubscriptions,
  scheduleBatchedUpdate,
  useEffect,
} from "../hooks";

/**
 * createContext函数 - 创建一个Context对象
 *
 * 用于创建一个上下文对象，实现组件树中数据的共享而无需通过props逐层传递
 * 返回一个包含Provider组件的上下文对象，类似React的Context API
 *
 * 工作原理:
 * 1. 为每个上下文创建唯一标识符(Symbol)和初始值
 * 2. 提供Provider组件用于在组件树中注入值
 * 3. 维护订阅系统，在上下文值变化时通知所有消费组件
 *
 * @param defaultValue 上下文的默认值，当没有匹配的Provider时使用
 * @returns 包含Provider组件的上下文对象
 */
export function createContext<T>(defaultValue: T) {
  // 创建唯一的上下文标识符
  const contextId = Symbol("context");
  // 在全局上下文映射中存储默认值
  contextMap.set(contextId, defaultValue);
  // 初始化订阅该上下文的组件集合
  contextSubscriptions.set(contextId, new Set());

  // 创建Provider组件 - 用于在组件树中注入上下文值
  const Provider = ({ value, children }: { value: T; children: any }) => {
    // 获取当前上下文值
    const prevValue = contextMap.get(contextId);

    // 检查值是否有变化，只在值变化时触发更新
    if (!Object.is(prevValue, value)) {
      // 更新全局上下文映射中的值
      contextMap.set(contextId, value);
      // 获取所有订阅该上下文的组件
      const subscribers = contextSubscriptions.get(contextId);
      if (subscribers) {
        // 创建副本避免迭代过程中的集合修改问题
        const subscribersCopy = [...subscribers];
        // 通知所有订阅组件更新
        for (const component of subscribersCopy) {
          if (component && !component.isUpdating) {
            scheduleBatchedUpdate(component, -1);
          }
        }
      }
    }

    // 使用useEffect处理Provider卸载时的清理
    useEffect(() => {
      return () => {
        // 当Provider卸载时，如果没有其他Provider使用此上下文，恢复默认值
        if (contextMap.get(contextId) !== defaultValue) {
          contextMap.set(contextId, defaultValue);
          // 通知所有订阅组件关于默认值的更新
          const subscribers = contextSubscriptions.get(contextId);
          if (subscribers) {
            const subscribersCopy = [...subscribers];
            for (const component of subscribersCopy) {
              if (component && !component.isUpdating) {
                scheduleBatchedUpdate(component, -1);
              }
            }
          }
        }
      };
    }, []);

    // 渲染子组件，不添加额外DOM节点
    return createElement("fragment", null, children);
  };

  // 返回上下文对象，包含Provider组件和内部上下文ID
  return {
    Provider,
    _contextId: contextId,
    displayName: "", // 用于开发工具显示，目前未使用
  };
}
